/* jshint esversion:6 */

/**
 * @author: errorcpp@qq.com
 */

require("./xlib_ByteBuffer");

var xwindow = ("undefined" != typeof(window)) ? window : global;
xwindow.xlib = xwindow.xlib || {};
let xlib = xwindow.xlib;


class ByteStream {
    constructor() {
        this._buffer    = new xlib.ByteBuffer();   // 实际的buffer
        this._read_pos  = 0;                       // 读游标
        this._write_pos = 0;                       // 写游标
    }

    /**
     * @brief: 获取读游标 
     */
    SetReadPos(read_pos) {
        this._read_pos = read_pos;
    }

    /**
     * @brief: 获取读游标
     */
    GetReadPos() {
        return this._read_pos;
    }

    /**
     * @brief: 设置写游标
     */
    SetWritePos(write_pos) {
        this._write_pos = write_pos;
    }

    /**
     * @brief: 读取写游标
     */
    GetWritePos() {
        return this._write_pos;
    }

    /**
     * @brief: 获取可读数据长度
     */
    GetReadableSize() {
        return this._write_pos - this._read_pos;
    }

    
    ReadU8() {
        let v = this._buffer.ReadU8(this._read_pos);
        this._read_pos += 1;

        return v;
    }

    ReadU16()  {
        let v = this._buffer.ReadU16(this._read_pos);
        this._read_pos += 2;

        return v;
    }

    ReadU32() {
        let v = this._buffer.ReadU32(this._read_pos);
        this._read_pos += 4;

        return v;
    }

    ReadI8()  {
        let v = this._buffer.ReadI8(this._read_pos);
        this._read_pos += 1;

        return v;
    }

    ReadI16()  {
        let v = this._buffer.ReadI16(this._read_pos);
        this._read_pos += 2;

        return v;
    }

    ReadI32() {
        let v = this._buffer.ReadI32(this._read_pos);
        this._read_pos += 4;

        return v;
    }

    WriteU8(u8) {
        this._buffer.Resize(this._write_pos + 1);
        this._buffer.WriteU8(u8, this._write_pos);
        this._write_pos += 1;
    }

    WriteU16(u16) {
        this._buffer.Resize(this._write_pos + 2);
        this._buffer.WriteU16(u16, this._write_pos);
        this._write_pos += 2;
    }

    WriteU32(u32) {
        this._buffer.Resize(this._write_pos + 4);
        this._buffer.WriteU32(u32, this._write_pos);
        this._write_pos += 4;
    }

    WriteI8(i8) {
        this._buffer.Resize(this._write_pos + 1);
        this._buffer.WriteI8(i8, this._write_pos);
        this._write_pos += 1;
    }

    WriteI16(i16) {
        this._buffer.Resize(this._write_pos + 2);
        this._buffer.WriteI16(i16, this._write_pos);
        this._write_pos += 2;
    }

    WriteI32(i32) {
        this._buffer.Resize(this._write_pos + 4);
        this._buffer.WriteI32(i32, this._write_pos);
        this._write_pos += 4;
    }

    ReadI64() {
        xlib.warn("ReadI64 not support!");

        return 0;
    }

    ReadU64() { 
        let h     = this.ReadI32();
        let l     = this.ReadI32();
        let l_str = l.toString();

        // 低位补满0
        for(let n = 8 - l_str.length; n > 0; --n) {
            l_str = "0" + l_str;
        }

        let s = h.toString() + l_str;
        let n = Number(s);

        return n;
    }

    WriteI64() {
        xlib.warn("64bit number not support!");
        this.WriteI32(0);
        this.WriteI32(0);
    }

    WriteU64() {
        xlib.warn("64bit number not support!");
        this.WriteU32(0);
        this.WriteU32(0);
    }

    /**
     * @brief: 读取一个ArrayBuffer
     * @param {number} byte_count: 比特数 
     */
    ReadArrayBuffer(byte_count) {
        //let arr_buf = new ArrayBuffer(byte_count);
        let arr_buf = this._buffer.ReadArrayBuffer(byte_count, this._read_pos);
        this._read_pos += byte_count;

        return arr_buf;
    }

    /**
     * @brief: 读取一个Uint8Array
     * @param {number} byte_count: 比特数 
     */
    ReadUint8Array(byte_count) {
        let arr_buff = this.ReadArrayBuffer(byte_count);
        let arr_u8   = new Uint8Array(arr_buff);

        return arr_u8;
    }

    /**
     * @brief: 写入一个ArrayBuffer
     * @param {ArrayBuffer} arr_buff 
     */
    WriteArrayBuffer(arr_buff) {
        this._buffer.Resize(this._write_pos + arr_buff.byteLength);
        this._buffer.WriteArrayBuffer(arr_buff, this._write_pos);
        this._write_pos += arr_buff.byteLength;
    }

    /**
     * @brief: 写入一个Uint8Array
     * @param {Uint8Array} arr_u8
     */
    WriteUint8Array(arr_u8) {
        this.WriteArrayBuffer(arr_u8.buffer);
    }
}

/**
 * @brief: 单元测试
 */
ByteStream.UnitTest = function() {
    let stream = new ByteStream();
    let test_data = [];
    let count_of_i8  = 0;
    let count_of_i16 = 0;
    let count_of_i32 = 0;
    let count_of_u8  = 0;
    let count_of_u16 = 0;
    let count_of_u32 = 0;
    for(let n = xlib.MIN_INT8; n <= xlib.MAX_INT8; ++n) {
        test_data.push(n);
        stream.WriteI8(n);
        count_of_i8++;
    }

    for(let n = xlib.MIN_INT16; n <= xlib.MAX_INT16; ++n) {
        test_data.push(n);
        stream.WriteI16(n);
        count_of_i16++;
    }

    for(let n = xlib.MIN_INT32; n <= xlib.MAX_INT32; ++n) {
        test_data.push(n);
        stream.WriteI32(n);
        count_of_i32++;
        if((n < 0) && (Math.random() > 0.01)) n = 1;
        if(Math.random() > 0.0005) n = n + parseInt(n * 1.5);
    }

    for(let n = xlib.MIN_UINT8; n <= xlib.MAX_UINT8; ++n) {
        test_data.push(n);
        stream.WriteU8(n);
        count_of_u8++;
    }

    for(let n = xlib.MIN_UINT16; n <= xlib.MAX_UINT16; ++n) {
        test_data.push(n);
        stream.WriteU16(n);
        count_of_u16++;
    }

    for(let n = xlib.MIN_UINT32; n <= xlib.MAX_UINT32; ++n) {
        test_data.push(n);
        stream.WriteU32(n);
        count_of_u32++;
        if((n < 0) && (Math.random() > 0.01)) n = 1;
        if(Math.random() > 0.0005) n = n + parseInt(n * 1.5);
    }

    ////////////////////////////////////////////////////////////////
    //let last_index = 0;
    //for(let n = 0; n < count_of_i8; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadI8());
    //}
    //last_index += count_of_i8;
    //for(let n = last_index; n < last_index + count_of_i16; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadI16());
    //}
    //last_index += count_of_i16;
    //for(let n = last_index; n < last_index + count_of_i32; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadI32());
    //}
    //last_index += count_of_i32;
    //for(let n = last_index; n < last_index + count_of_u8; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadU8());
    //}
    //last_index += count_of_u8;
    //for(let n = last_index; n < last_index + count_of_u16; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadU16());
    //}
    //last_index += count_of_u16;
    //for(let n = last_index; n < last_index + count_of_u32; ++n) {
    //    xlib.assert(test_data[n] == stream.ReadU32());
    //}

    //console.log(stream);
};

if(xlib.__enable_auto_unit_test)
    ByteStream.UnitTest();

// 导出
xlib.ByteStream = ByteStream;